/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.clazz; import java.util.Map; import java.util.HashMap; import java.util.Collection; import java.util.Collections; import java.lang.ref.SoftReference; import java.lang.reflect.*; import org.openide.src.*; /** The implementation of the class element for * class objects. Presents data about the class - * uses java reflection to obtain needed information. * * @author Dafe Simonek */ final class ClassElementImpl extends MemberElementImpl implements ClassElement.Impl { /** Empty array of initializers - constant to return from getInitializers() */ private static final InitializerElement[] EMPTY_INITIALIZERS = new InitializerElement[0]; private static final Object[] EMPTY_ARRAY = new Object[0]; /** Identifier of superclass of this class element, * can be empty */ private Identifier superClass; /** Array of identifiers for interfaces */ private Identifier[] interfaces; /** Fields of this class element */ private SoftReference fields; /** Inner classes of this class element */ private SoftReference inners; /** Contructors of this class element */ private SoftReference constructors; /** Methods of this class element */ private SoftReference methods; /** One JavaDoc empty implementation for all objects */ private static final ClassJavaDocImpl.Class CLASS_JAVADOC_IMPL = new ClassJavaDocImpl.Class (); static final long serialVersionUID =-8717988834353784544L; /** Default constructor. */ public ClassElementImpl (final Class data) { super(data); } /** Not supported. Throws source exception */ public void setSuperclass(Identifier superClass) throws SourceException { throw new SourceException(); } public Identifier getSuperclass() { if (superClass == null) { Class sc = ((Class)data).getSuperclass(); superClass = Identifier.create(sc == null ? "" : sc.getName()); // NOI18N } return superClass; } /** Not supported. Throws Source Exception */ public void setClassOrInterface(boolean isClass) throws SourceException { throw new SourceException(); } public boolean isClassOrInterface() { return !((Class)data).isInterface(); } /** Not supported. Throws SourceException. */ public void changeInitializers (InitializerElement[] elems, int action) throws SourceException { throw new SourceException(); } /** Not available. Always returns empty array */ public InitializerElement[] getInitializers () { return EMPTY_INITIALIZERS; } /** Changes set of elements. * @param elems elements to change * @exception SourceException if the action cannot be handled */ public void changeFields (FieldElement[] elems, int action) throws SourceException { throw new SourceException(); } public FieldElement[] getFields () { Map fieldsMap = (fields == null) ? null : (Map)fields.get(); if (fieldsMap == null) { // soft ref null, we must recreate fieldsMap = createFieldsMap(); fields = new SoftReference(fieldsMap); } return (FieldElement[])fieldsMap.values().toArray(new FieldElement[0]); } /** Finds a field with given name. * @param name the name of field to look for * @return the element or null if field with such name does not exist */ public FieldElement getField (Identifier name) { Map fieldsMap = (fields == null) ? null : (Map)fields.get(); if (fieldsMap == null) { // soft ref null, we must recreate fieldsMap = createFieldsMap(); fields = new SoftReference(fieldsMap); } return (FieldElement)fieldsMap.get(name); } /** Changes set of elements. * @param elems elements to change * @exception SourceException if the action cannot be handled */ public void changeMethods (MethodElement[] elems, int action) throws SourceException { throw new SourceException(); } public MethodElement[] getMethods () { Map methodsMap = (methods == null) ? null : (Map)methods.get(); if (methodsMap == null) { // soft ref null, we must recreate methodsMap = createMethodsMap(); methods = new SoftReference(methodsMap); } return (MethodElement[])methodsMap.values().toArray(new MethodElement[0]); } /** Finds a method with given name and argument types. * @param name the name of field to look for * @param arguments for the method * @return the element or null if such method does not exist */ public MethodElement getMethod (Identifier name, Type[] arguments) { Map methodsMap = (methods == null) ? null : (Map)methods.get(); if (methodsMap == null) { // soft ref null, we must recreate methodsMap = createMethodsMap(); methods = new SoftReference(methodsMap); } return (MethodElement) methodsMap.get(new MethodElement.Key(name, arguments)); } /** Changes set of elements. * @param elems elements to change * @exception SourceException if the action cannot be handled */ public void changeConstructors (ConstructorElement[] elems, int action) throws SourceException { throw new SourceException(); } public ConstructorElement[] getConstructors () { Map constructorsMap = (constructors == null) ? null :(Map)constructors.get(); if (constructorsMap == null) { // soft ref null, we must recreate constructorsMap = createConstructorsMap(); constructors = new SoftReference(constructorsMap); } return (ConstructorElement[])constructorsMap.values(). toArray(new ConstructorElement[0]); } /** Finds a constructor with argument types. * @param arguments for the method * @return the element or null if such method does not exist */ public ConstructorElement getConstructor (Type[] arguments) { Map constructorsMap = (constructors == null) ? null :(Map)constructors.get(); if (constructorsMap == null) { // soft ref null, we must recreate constructorsMap = createConstructorsMap(); constructors = new SoftReference(constructorsMap); } return (ConstructorElement) constructorsMap.get(new ConstructorElement.Key(arguments)); } /** Changes set of elements. * @param elems elements to change * @exception SourceException if the action cannot be handled */ public void changeClasses (ClassElement[] elems, int action) throws SourceException { throw new SourceException(); } public ClassElement[] getClasses () { Map innersMap = (inners == null) ? null : (Map)inners.get(); if (innersMap == null) { // soft ref null, we must recreate innersMap = createInnersMap(); inners = new SoftReference(innersMap); } return (ClassElement[])innersMap.values().toArray(new ClassElement[0]); } /** Finds an inner class with given name. * @param name the name to look for * @return the element or null if such class does not exist */ public ClassElement getClass (Identifier name) { Map innersMap = (inners == null) ? null : (Map)inners.get(); if (innersMap == null) { // soft ref null, we must recreate innersMap = createInnersMap(); inners = new SoftReference(innersMap); } return (ClassElement)innersMap.get(name); } /** Changes interfaces this class implements (or extends). * @param ids identifiers to change * @exception SourceException if the action cannot be handled */ public void changeInterfaces (Identifier[] ids, int action) throws SourceException { throw new SourceException(); } /** @return all interfaces which the class implements or interface extends. */ public Identifier[] getInterfaces () { if (interfaces == null) { // create identifier array for interfaces Class[] reflIntfs = ((Class)data).getInterfaces(); interfaces = new Identifier[reflIntfs.length]; for (int i = 0; i < reflIntfs.length; i++) { interfaces[i] = Identifier.create(reflIntfs[i].getName()); } } return interfaces; } /** @return class documentation. */ public JavaDoc.Class getJavaDoc() { return CLASS_JAVADOC_IMPL; } /******** non public methods ***********/ /** Creates map for fields consisting of identifier - field entries */ private Map createFieldsMap () { // obtain field array Field[] reflFields = null; try { reflFields = ((Class)data).getDeclaredFields(); } catch (Throwable exc) { // rethrow only ThreadDeath, ignore otherwise if (exc instanceof ThreadDeath) throw (ThreadDeath)exc; reflFields = new Field[0]; } // create map FieldElement curFE = null; Map result = new HashMap(reflFields.length); for (int i = 0; i < reflFields.length; i++) { // filter out methods added by compiler if (!addedByCompiler(reflFields[i])) { curFE = new FieldElement(new FieldElementImpl(reflFields[i]), (ClassElement)element); result.put(curFE.getName(), curFE); } } return result; } /** Creates map for inner classes of this class, * consisting of identifier - class element entries */ private Map createInnersMap () { // obtain array of interfaces and inner classes Class[] reflInners = null; try { reflInners = ((Class)data).getDeclaredClasses(); } catch (Throwable exc) { // rethrow only ThreadDeath, ignore otherwise if (exc instanceof ThreadDeath) throw (ThreadDeath)exc; reflInners = new Class[0]; } // create map ClassElement curCE = null; Map result = new HashMap(reflInners.length); for (int i = 0; i < reflInners.length; i++) { curCE = new ClassElement(new ClassElementImpl(reflInners[i]), (ClassElement)element); result.put(curCE.getName(), curCE); } return result; } /** Creates map for constructors of this class, * consisting of constructor key - constructor element entries */ private Map createConstructorsMap () { // obtain constructors array Constructor[] reflCons = null; try { reflCons = ((Class)data).getDeclaredConstructors(); } catch (Throwable exc) { // rethrow only ThreadDeath, ignore otherwise if (exc instanceof ThreadDeath) throw (ThreadDeath)exc; reflCons = new Constructor[0]; } // create map ConstructorElement curCE = null; Map result = new HashMap(reflCons.length); for (int i = 0; i < reflCons.length; i++) { curCE = new ConstructorElement(new ConstructorElementImpl(reflCons[i]), (ClassElement)element); result.put(new ConstructorElement.Key(curCE), curCE); } return result; } /** Creates map for methods of this class, * consisting of method key - method element entries */ private Map createMethodsMap () { // obtain methods array Method[] reflMethods = null; try { reflMethods = ((Class)data).getDeclaredMethods(); } catch (Throwable exc) { // rethrow only ThreadDeath, ignore otherwise if (exc instanceof ThreadDeath) throw (ThreadDeath)exc; reflMethods = new Method[0]; } // create map MethodElement curME = null; Map result = new HashMap(reflMethods.length); for (int i = 0; i < reflMethods.length; i++) { // filter out methods added by compiler if (!addedByCompiler(reflMethods[i])) { curME = new MethodElement(new MethodElementImpl(reflMethods[i]), (ClassElement)element); result.put(new MethodElement.Key(curME), curME); } } return result; } public Object readResolve() { return new ClassElement(this, (SourceElement)null); } /** @return true if given member was generated automatically by compiler, * false otherwise. Decision is made by inspecting the name of the member. */ private static boolean addedByCompiler (Member member) { String name = member.getName(); return name.indexOf('$') >= 0; } } /* * Log * 14 src-jtulach1.13 1/13/00 David Simonek i18n * 13 src-jtulach1.12 1/5/00 David Simonek #2642 * 12 src-jtulach1.11 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 11 src-jtulach1.10 8/9/99 Ian Formanek Generated Serial Version * UID * 10 src-jtulach1.9 6/9/99 Petr Hrebejk Empty JavaDoc * implementation added. * 9 src-jtulach1.8 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 8 src-jtulach1.7 5/12/99 Petr Hamernik ide.src.Identifier * updated * 7 src-jtulach1.6 3/31/99 David Simonek setClassOrInterface now * throws SourceException * 6 src-jtulach1.5 3/26/99 David Simonek properties, actions * completed, more robust now * 5 src-jtulach1.4 2/17/99 Petr Hamernik serialization changed. * 4 src-jtulach1.3 2/10/99 David Simonek * 3 src-jtulach1.2 2/3/99 David Simonek * 2 src-jtulach1.1 1/29/99 David Simonek * 1 src-jtulach1.0 1/22/99 David Simonek * $ */